package org.checkboo.hopefullyengine.loaders;

import java.util.LinkedList;

import org.checkboo.hopefullyengine.inversekinematics.Animation;
import org.checkboo.hopefullyengine.inversekinematics.Bone;
import org.checkboo.hopefullyengine.inversekinematics.KeyFrame;
import org.checkboo.hopefullyengine.inversekinematics.Skeleton;
import org.checkboo.hopefullyengine.inversekinematics.Track;
import org.checkboo.math.FloatMath;
import org.checkboo.math.Quaternion;
import org.checkboo.math.Vector3f;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class OgreSkeletonHandler extends DefaultHandler {
	private LinkedList<Bone> bones;
	private LinkedList<Animation> animations;
	private LinkedList<Track> tracks;
	private LinkedList<KeyFrame> keyFrames;
	private Skeleton skeleton;
	private boolean inBone = false;
	private boolean inKeyFrame = false;
	private boolean inRotation = false;
	private boolean inRotate = false;
	private boolean inAnimation = false;
	private boolean rootBone = true;
	private Bone tmpBone;
	private Animation tmpAnimation;
	private KeyFrame tmpKeyFrame;
	private Track tmpTrack;
	private float tmpAngle;
	private Vector3f tmpAxis;
	private Quaternion tmpQuat;
	
	
	@Override
	public void startElement(String uri, String localName, String qName,
			Attributes attributes) throws SAXException {
		if(qName.equalsIgnoreCase("skeleton"))
			this.skeleton = new Skeleton();
		
		if(qName.equalsIgnoreCase("bones"))
			this.bones = new LinkedList<Bone>();
		
		if(qName.equalsIgnoreCase("bone")){
			inBone = true;
			this.tmpBone = new Bone(Integer.parseInt(attributes.getValue("id")), attributes.getValue("name"));			
		}
		
		if(qName.equalsIgnoreCase("position")){
			this.tmpBone.setPosition(new Vector3f(Float.parseFloat(attributes.getValue("x")), 
																	Float.parseFloat(attributes.getValue("y")), 
																	Float.parseFloat(attributes.getValue("z"))));
			this.tmpBone.setLength((new Vector3f(Float.parseFloat(attributes.getValue("x")), 
					Float.parseFloat(attributes.getValue("y")), 
					Float.parseFloat(attributes.getValue("z")))).magnitude());
		}
		
		if(qName.equalsIgnoreCase("rotation")){
			this.tmpAngle = Float.parseFloat(attributes.getValue("angle"));
			this.inRotation = true;
		}
		
		if(qName.equalsIgnoreCase("axis")){
			this.tmpQuat = new Quaternion();
			this.tmpQuat.fromAngleAxis(FloatMath.radToDeg(this.tmpAngle), new Vector3f(Float.parseFloat(attributes.getValue("x")), 
																	Float.parseFloat(attributes.getValue("y")), 
																	Float.parseFloat(attributes.getValue("z"))));
			if(inRotation){
				this.tmpBone.setDirection(this.tmpQuat);
			}
			else if(inRotate){
				this.tmpKeyFrame.setRotation(this.tmpQuat);
			}
			
		}
		
		if(qName.equalsIgnoreCase("boneparent")){
			if(this.rootBone){
				this.skeleton.setRoot(getBoneByName(attributes.getValue("parent")));
				this.rootBone = false;
			}
			getBoneByName(attributes.getValue("parent")).addChild(getBoneByName(attributes.getValue("bone")));
		}
		
		if(qName.equalsIgnoreCase("animations"))
			this.animations = new LinkedList<Animation>();
		
		if(qName.equalsIgnoreCase("animation")){
			this.tmpAnimation = new Animation(attributes.getValue("name"), (long)(Float.parseFloat(attributes.getValue("length"))*1000));
		}
		
		if(qName.equalsIgnoreCase("tracks"))
			this.tracks = new LinkedList<Track>();
		
		if(qName.equalsIgnoreCase("track")){
			this.tmpTrack = new Track(attributes.getValue("bone"));
		}
		
		if(qName.equalsIgnoreCase("keyframes"))
			this.keyFrames = new LinkedList<KeyFrame>();
		
		if(qName.equalsIgnoreCase("keyframe"))
			this.tmpKeyFrame = new KeyFrame((long)(Float.parseFloat(attributes.getValue("time"))*1000));
		
		if(qName.equalsIgnoreCase("translate"))
			this.tmpKeyFrame.setTranslation(new Vector3f(Float.parseFloat(attributes.getValue("x")), 
										Float.parseFloat(attributes.getValue("y")), 
										Float.parseFloat(attributes.getValue("z"))));
		
		if(qName.equalsIgnoreCase("rotate")){
			this.tmpAngle = Float.parseFloat(attributes.getValue("angle"));
			this.inRotate = true;
		}
		
		if(qName.equalsIgnoreCase("scale"))
			this.tmpKeyFrame.setScale(new Vector3f(Float.parseFloat(attributes.getValue("x")), 
										Float.parseFloat(attributes.getValue("y")), 
										Float.parseFloat(attributes.getValue("z"))));
		
		super.startElement(uri, localName, qName, attributes);
	}
	
	@Override
	public void endElement(String uri, String localName, String qName)
			throws SAXException {
		if(qName.equalsIgnoreCase("bone"))
			this.bones.add(this.tmpBone);
		if(qName.equalsIgnoreCase("bones"))
			this.skeleton.setBones(this.bones);
		if(qName.equalsIgnoreCase("animation"))
			this.animations.add(this.tmpAnimation);
		if(qName.equalsIgnoreCase("animations"))
			this.skeleton.setAnimations(this.animations);
		if(qName.equalsIgnoreCase("track")){
			this.tracks.add(this.tmpTrack);
		}
		if(qName.equalsIgnoreCase("tracks"))
			this.tmpAnimation.setTracks(this.tracks);
		if(qName.equalsIgnoreCase("keyframe")){
			this.keyFrames.add(this.tmpKeyFrame);
		}
		if(qName.equalsIgnoreCase("keyframes"))
			this.tmpTrack.setKeyFrames(this.keyFrames);
		if(qName.equalsIgnoreCase("rotation"))
			this.inRotation = false;
		if(qName.equalsIgnoreCase("rotate"))
			this.inRotate = false;
		//if(qName.equalsIgnoreCase("bonehierarchy"))
			//this.skeleton.initSkeleton();
		super.endElement(uri, localName, qName);
	}
	
	private Bone getBoneByName(String name){
		for(Bone b : this.bones){
			if(b.getName().equalsIgnoreCase(name))
				return b;
		}
		return null;
	}

	public Skeleton getSkeleton() {
		return skeleton;
	}

	public void setSkeleton(Skeleton skeleton) {
		this.skeleton = skeleton;
	}
}
